#include "globals.h"

int main()
{

	char IPclient[INET_ADDRSTRLEN],IPserver[INET_ADDRSTRLEN],filename[100]="\0",buf[100]="\0";
	int SERVER_PORT,Win,seed,mu,i=1,j,sockfd;
	float p;
	FILE * fp;
	struct in_addr ipv4_addr;
	struct ifi_info	*ifi, *ifihead;	
	struct sockaddr * sa;
	struct sockaddr_in cliaddr, servaddr;
	char * ptr;
	
	if((fp=fopen("client.in","r"))==NULL)
	{
		printf("client.in not found\n");
		exit(1);
	}
	else
	{
		while(Fgets(buf,100,fp)!=NULL)
		{
			int flags = 0;

			if(i!=1 && i!=3)
			{
				for(j=0;buf[j]!='\0';j++)
				{
					if(isdigit(buf[j]))
						continue;
					else if(flags==-1)
						break;
					else if(i==6 && buf[j]=='.')
						flags=-1;					
					else break;	
				}
				if(j!=strlen(buf)-1)
					flags=1;

			}

			switch(i)
			{
				case 1: 
					strcpy(IPserver,buf);
					IPserver[strlen(buf)-1]='\0';
					//printf("%s\n",IPserver);
					if(inet_pton(AF_INET, IPserver,&ipv4_addr.s_addr)<=0)
					{
						printf("Error server.in :: Line 1 :: contains invalid Server IP\n");
						exit(1);
					}	
					i++;
					break;
				case 2:
					if(flags || (SERVER_PORT=atoi(buf))==0)
					{
						printf("Error server.in :: Line 2 :: Invalid Port number\n");
						exit(1);
					}	
					i++;
					break;
				case 3:
					strcpy(filename,buf);
					filename[strlen(buf)-1]='\0';
					if(fopen(filename,"r")==NULL)
					{
						printf("Error server.in :: Line 3 :: File not found\n");	
						exit(1);
					}	
					i++;
					break;	
				case 4:
					if(flags || (Win=atoi(buf))==0)
					{
						printf("Error server.in :: Line 4 :: Invalid Receiving Sliding Window Size\n");
						exit(1);
					}	
					i++;
					break;	
				case 5:
					if(flags || (seed=atoi(buf))==0)
					{
						printf("Error server.in :: Line 5 :: Invalid Seed value\n");
						exit(1);
					}	
					i++;					
					break;	
				case 6:
					p=atof(buf);
					if(flags==1 || p<0.0 || p>1.0)
					{
						printf("Error server.in :: Line 6 :: Invalid Probability value\n");
						exit(1);
					}	
					i++;									
					break;	
				case 7:
					if(flags || (mu=atoi(buf))==0)
					{
						printf("Error server.in :: Line 7 :: Invalid Mean value\n");
						exit(1);
					}	
					i++;								
					break;	
					
			}	
			for(j=0;j<100;j++)
				buf[j]='\0';
		}
//		printf("%s %d %s %d %d %f %d\n",IPserver, SERVER_PORT, filename, Win, seed, p, mu);
		fclose(fp);
	}
	int flags=3;
	for (ifihead = ifi = Get_ifi_info_plus(AF_INET, 1),i=0;ifi != NULL; ifi = ifi->ifi_next,i++) 
	{
		char ip_addr[INET_ADDRSTRLEN]="\0",net_msk[INET_ADDRSTRLEN]="\0",sub_msk[INET_ADDRSTRLEN]="\0";
		int p1,p2;
		sa = ifi->ifi_addr;
		strcpy(ip_addr,Sock_ntop_host(sa, sizeof(*sa)));
		sa =  ifi->ifi_ntmaddr;
		strcpy(net_msk,Sock_ntop_host(sa, sizeof(*sa)));

		for(p1=0,p2=0,j=0;j<4;j++,p1++,p2++) //Finding the subnet mask
		{
			int a,b,k;
			char s1[4]="\0",s2[4]="\0";
			for(k=0;ip_addr[p1]!='.' && k<4;k++)
				s1[k]=ip_addr[p1++];
			for(k=0;net_msk[p2]!='.'&&k<4;k++)
				s2[k]=net_msk[p2++];

			a=atoi(s1);
			b=atoi(s2);	

			sprintf(s1,"%d%s",a&b,"\0");
			if(j)
				strcat(sub_msk,".");	
			strcat(sub_msk,s1);			
		}

		printf("\nClient Interface %d :-\nIP Address :: %s\nNetwork Mask :: %s\nSubnet Mask :: %s\n\n",(i+1),ip_addr,net_msk,sub_msk);

	//	printf("%s %s %d\n",IPserver,ip_addr,strcmp(IPserver,ip_addr)==0);
		if(strcmp(IPserver,ip_addr)==0) //Server on same host
		{
			strcpy(IPserver,"127.0.0.1");
			strcpy(IPclient,ip_addr);
			printf("Client and Server are on the same host\nIPclient :: %s IPserver :: %s \n",IPclient,IPserver);
			flags=1;
			break;
		}
		else //Check if Server is local
		{
			char check_sub_msk[INET_ADDRSTRLEN]="\0";
			for(p1=0,p2=0,j=0;j<4;j++,p1++,p2++) //Computing NetworkMaskClient & IPserver = SubMaskClient
			{
				int a,b,k;
				char s1[4]="\0",s2[4]="\0";
				for(k=0;IPserver[p1]!='.' && k<4;k++)
					s1[k]=IPserver[p1++];
				for(k=0;net_msk[p2]!='.'&&k<4;k++)
					s2[k]=net_msk[p2++];

				a=atoi(s1);
				b=atoi(s2);	

				sprintf(s1,"%d%s",a&b,"\0");
				if(j)
					strcat(check_sub_msk,".");	
				strcat(check_sub_msk,s1);			
			}
//			printf("Check :: %s %s\n",check_sub_msk,sub_msk);
			if(strcmp(check_sub_msk,sub_msk)==0)
			{
				strcpy(IPclient,ip_addr);
				printf("Client and Server are local i.e. in the same subnet\nIPclient :: %s IPserver :: %s\n",IPclient,IPserver);
				flags=2;
				break;
			}
		}
		if(ifi->ifi_next==NULL)		//Not local not same host
		{
			strcpy(IPclient,ip_addr);
			printf("Client and Server are not local\nIPclient :: %s IPserver :: %s \n",IPclient,IPserver);
		}
	}

	free_ifi_info_plus(ifihead);

	sockfd=Socket(AF_INET,SOCK_DGRAM,0);
	
	bzero(&cliaddr,sizeof(cliaddr));
	cliaddr.sin_family=AF_INET;
	inet_pton(AF_INET, IPclient, &cliaddr.sin_addr);
	cliaddr.sin_port=htons(0);
	Bind(sockfd, (SA *) & cliaddr, sizeof(cliaddr));
	
	struct sockaddr_in sock_nm;
	socklen_t len;
	len=sizeof(sock_nm);
	getsockname(sockfd,(SA*)&sock_nm,&len);
	printf("\nClient Socket created and Binded\nIPClient:Portno :- %s \n",Sock_ntop((SA*)&sock_nm, len));
	
	bzero(&servaddr,sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	inet_pton(AF_INET, IPserver, &servaddr.sin_addr);
	servaddr.sin_port=htons(SERVER_PORT);
	Connect(sockfd, (SA*) &servaddr, sizeof(servaddr));
	
	bzero(&sock_nm,sizeof(sock_nm));
	len=sizeof(sock_nm);
	getpeername(sockfd,(SA*)&sock_nm,&len);
	log_msg_int("\nAfter UDP Connect \nIPServer:Portno :- %s \n",Sock_ntop((SA*)&sock_nm, len));
	
	if(flags==1)
		flags=MSG_DONTROUTE;
	else
		flags=0;	
	send(sockfd,filename,100,flags);
	printf("Request sent for %s\n",filename);
	for(i=0;i<100;i++)
		buf[i]='\0';
	recv(sockfd,buf,100,flags);
	printf("Buf content %s\n",buf);	
	

	ptr=strchr(buf,':');
	strcpy(buf,(ptr+1));
	printf("Buf content %s\n",buf);	

	servaddr.sin_port=htons(atoi(buf));
//	printf("S %d\n",atoi(buf));
	Connect(sockfd, (SA*) &servaddr, sizeof(servaddr));
	printf("New connection established with Server at Port no %s\n", buf);
	strcpy(buf,"ACK\0");
	send(sockfd,buf,100,flags);
	log_msg("ACK sent to Server\n");
	
	while(1)
	{
	recv(sockfd,buf,100,flags);
	if(buf[0]==EOF)
		break;
	else
		printf("%s",buf);	
	}
	close(sockfd);
return(0);
}
